/*
 * @Author: wushengran
 * @Date: 2024-06-17 14:24:56
 * @Description:
 *
 * Copyright (c) 2024 by atguigu, All Rights Reserved.
 */
#include "lcd.h"
#include "lcd_font.h"

// 1. �������Ʋ���
// 1.1 ��ʼ��
void LCD_Init(void)
{
    MX_FSMC_Init();

    LCD_Reset();

    LCD_BGOn();

    LCD_RegConfig();
}

// 1.1.1 ��λ
void LCD_Reset(void)
{
    // ֱ�ӽ�PG15����
    GPIOG->ODR &= ~GPIO_ODR_ODR15;

    // �����ӳ٣�Ȼ������
    HAL_Delay(100);
    GPIOG->ODR |= GPIO_ODR_ODR15;

    HAL_Delay(100);
}

// 1.1.2 ���ر���
void LCD_BGOn(void)
{
    // PB0����ߵ�ƽ����������LED
    GPIOB->ODR |= GPIO_ODR_ODR0;
}
void LCD_BGOff(void)
{
    // PB0����͵�ƽ���رձ���LED
    GPIOB->ODR &= ~GPIO_ODR_ODR0;
}

// 1.1.3 ��ʼ��LCD�Ĵ���
void LCD_RegConfig(void)
{
    LCD_WriteCmd(0xE0);
    LCD_WriteData(0x00);
    LCD_WriteData(0x07);
    LCD_WriteData(0x10);
    LCD_WriteData(0x09);
    LCD_WriteData(0x17);
    LCD_WriteData(0x0B);
    LCD_WriteData(0x41);
    LCD_WriteData(0x89);
    LCD_WriteData(0x4B);
    LCD_WriteData(0x0A);
    LCD_WriteData(0x0C);
    LCD_WriteData(0x0E);
    LCD_WriteData(0x18);
    LCD_WriteData(0x1B);
    LCD_WriteData(0x0F);

    /* 2. ���ûҽ׵�ѹ�Ե���TFT����٤�����ԣ���У׼ */
    LCD_WriteCmd(0XE1);
    LCD_WriteData(0x00);
    LCD_WriteData(0x17);
    LCD_WriteData(0x1A);
    LCD_WriteData(0x04);
    LCD_WriteData(0x0E);
    LCD_WriteData(0x06);
    LCD_WriteData(0x2F);
    LCD_WriteData(0x45);
    LCD_WriteData(0x43);
    LCD_WriteData(0x02);
    LCD_WriteData(0x0A);
    LCD_WriteData(0x09);
    LCD_WriteData(0x32);
    LCD_WriteData(0x36);
    LCD_WriteData(0x0F);

    /* 3.  Adjust Control 3 (F7h)  */
    /*LCD_WriteCmd(0XF7);
   LCD_WriteData(0xA9);
   LCD_WriteData(0x51);
   LCD_WriteData(0x2C);
   LCD_WriteData(0x82);*/
    /* DSI write DCS command, use loose packet RGB 666 */

    /* 4. ��Դ����1*/
    LCD_WriteCmd(0xC0);
    LCD_WriteData(0x11); /* ��٤����ѹ */
    LCD_WriteData(0x09); /* ��٤����ѹ */

    /* 5. ��Դ����2 */
    LCD_WriteCmd(0xC1);
    LCD_WriteData(0x02);
    LCD_WriteData(0x03);

    /* 6. VCOM���� */
    LCD_WriteCmd(0XC5);
    LCD_WriteData(0x00);
    LCD_WriteData(0x0A);
    LCD_WriteData(0x80);

    /* 7. Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
    LCD_WriteCmd(0xB1);
    LCD_WriteData(0xB0);
    LCD_WriteData(0x11);

    /* 8.  Display Inversion Control (B4h) ��������ѹ��ת�����ٵ�Ÿ��ţ�*/
    LCD_WriteCmd(0xB4);
    LCD_WriteData(0x02);

    /* 9.  Display Function Control (B6h)  */
    LCD_WriteCmd(0xB6);
    LCD_WriteData(0x0A);
    LCD_WriteData(0xA2);

    /* 10. Entry Mode Set (B7h)  */
    LCD_WriteCmd(0xB7);
    LCD_WriteData(0xc6);

    /* 11. HS Lanes Control (BEh) */
    LCD_WriteCmd(0xBE);
    LCD_WriteData(0x00);
    LCD_WriteData(0x04);

    /* 12.  Interface Pixel Format (3Ah) */
    LCD_WriteCmd(0x3A);
    LCD_WriteData(0x55); /* 0x55 : 16 bits/pixel  */

    /* 13. Sleep Out (11h) �ر�����ģʽ */
    LCD_WriteCmd(0x11);

    /* 14. ������Ļ�����RGB */
    LCD_WriteCmd(0x36);
    LCD_WriteData(0x08);

    HAL_Delay(120);

    /* 14. display on */
    LCD_WriteCmd(0x29);
}

// 1.2 д�������һ��ָ�
void LCD_WriteCmd(uint16_t cmd)
{
    *LCD_ADDR_CMD = cmd;
}

// 1.3 д���ݣ�����һ�����ݣ�
void LCD_WriteData(uint16_t data)
{
    *LCD_ADDR_DATA = data;
}

// 1.4 ������
uint16_t LCD_ReadData(void)
{
    return *LCD_ADDR_DATA;
}

// 2. ������������

// 2.1 ����ID��Ϣ
uint32_t LCD_ReadID(void)
{
    // ���ȷ��Ͷ�ȡID������
    LCD_WriteCmd(0x04);

    // ����������������ֽڵ�ID��Ϣ
    uint32_t id = 0;

    LCD_ReadData();

    // ���ζ�ȡ�����ֽڵ����ݣ�������id�Ķ�Ӧλ��
    id |= (LCD_ReadData() & 0xff) << 16;
    id |= (LCD_ReadData() & 0xff) << 8;
    id |= (LCD_ReadData() & 0xff);

    return id;
}

// 2.2 ��������Χ��������ʼ������꣨���кţ����Լ�����Ŀ��͸�
void LCD_SetArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
    // 1. �����з�Χ
    LCD_WriteCmd(0x2a);

    // 1.1 ���ÿ�ʼ��
    LCD_WriteData(x >> 8 & 0xff);
    LCD_WriteData(x & 0xff);

    // 1.2 ���ý�����
    LCD_WriteData((x + w - 1) >> 8 & 0xff);
    LCD_WriteData((x + w - 1) & 0xff);

    // 2. �����з�Χ
    LCD_WriteCmd(0x2b);

    // 2.1 ���ÿ�ʼ��
    LCD_WriteData(y >> 8 & 0xff);
    LCD_WriteData(y & 0xff);

    // 2.2 ���ý�����
    LCD_WriteData((y + h - 1) >> 8 & 0xff);
    LCD_WriteData((y + h - 1) & 0xff);
}

// 2.3 ����
void LCD_ClearAll(uint16_t color)
{
    // 1. ��������ΧΪȫ��
    LCD_SetArea(0, 0, LCD_W, LCD_H);

    // 2. ���Ӧ����Χ��������
    // 2.1 ��������
    LCD_WriteCmd(0x2c);

    // 2.2 ��ѭ�������������ص㣬����д������
    for (uint32_t i = 0; i < LCD_W * LCD_H; i++)
    {
        LCD_WriteData(color);
    }
}

// 3. �ϲ�����ӿ�
// 3.1 ��ʾһ��ASCII���ַ�
void LCD_WriteAsciiChar(uint16_t x, uint16_t y, uint16_t height, uint8_t c, uint16_t fColor, uint16_t bColor)
{
    // 1. ��ȷ������
    LCD_SetArea(x, y, height / 2, height);

    // 2. ����д���Դ�ָ��
    LCD_WriteCmd(0x2C);

    // 3. ���������������е����ص㣬�ж��Ƿ�Ϊ�ַ��ıʻ�
    // ���������С������ͬ��������Ѱ���ַ���Ӧ�ĵ���

    // �ȼ��㵱ǰ�ַ�c���ֿ������������λ��
    uint8_t index = c - ' ';

    // 3.1 ���������1608����1206����һ���ֽڱ�ʾһ�е���
    if (height == 16 || height == 12)
    {
        // ����ÿһ�У�ÿһ�У�˫��ѭ����
        for (uint8_t i = 0; i < height; i++)
        {
            // ���������С�����ֿ���ѡ��ǰ�ж�Ӧ�ĵ�i���ֽڣ�����ǵ�i�еĵ���
            uint8_t tempByte = (height == 16) ? ascii_1608[index][i] : ascii_1206[index][i];

            //  ������ǰ���е�ÿһ�У�ÿ�����ص� - �ֽ��е�ÿһλ��
            for (uint8_t j = 0; j < height / 2; j++)
            {
                // ÿ��ֻȡ���λ
                if (tempByte & 0x01)
                {
                    // �����1����ʾ������ɫ
                    LCD_WriteData(fColor);
                }
                else
                {
                    // �����0����ʾ������ɫ
                    LCD_WriteData(bColor);
                }
                // ����һλ
                tempByte >>= 1;
            }
        }
    }

    // 3.2 ���������2412���������ֽڱ�ʾһ�е���
    else if (height == 24)
    {
        // ����ÿһ�У�ÿһ�У�˫��ѭ����
        // i Ϊ�ֽڱ��
        for (uint8_t i = 0; i < height * 2; i++)
        {
            // ���������С�����ֿ���ѡ��ǰ�ж�Ӧ�ĵ�i���ֽ�
            uint8_t tempByte = ascii_2412[index][i];

            // ���ݵ�ǰi��ֵ���ж��ֽ��б�������λ���ݣ������Ļ�ֻ������4λ��
            uint8_t jCount = (i % 2) ? 4 : 8;

            //  ������ǰ�ֽ��е�ÿһ�У�ÿ�����ص� - �ֽ��е�ÿһλ��
            for (uint8_t j = 0; j < jCount; j++)
            {
                // ÿ��ֻȡ���λ
                if (tempByte & 0x01)
                {
                    // �����1����ʾ������ɫ
                    LCD_WriteData(fColor);
                }
                else
                {
                    // �����0����ʾ������ɫ
                    LCD_WriteData(bColor);
                }
                // ����һλ
                tempByte >>= 1;
            }
        }
    }

    // 3.3 ���������3216���������ֽڱ�ʾһ�е���
    else if (height == 32)
    {
        // ����ÿһ�У�ÿһ�У�˫��ѭ����
        for (uint8_t i = 0; i < height * 2; i++)
        {
            // ���������С�����ֿ���ѡ��ǰ�ж�Ӧ�ĵ�i���ֽڣ�����ǵ�i�еĵ���
            uint8_t tempByte = ascii_3216[index][i];

            //  ������ǰ�ֽ��е�ÿһ�У�ÿ�����ص� - �ֽ��е�ÿһλ��
            for (uint8_t j = 0; j < 8; j++)
            {
                // ÿ��ֻȡ���λ
                if (tempByte & 0x01)
                {
                    // �����1����ʾ������ɫ
                    LCD_WriteData(fColor);
                }
                else
                {
                    // �����0����ʾ������ɫ
                    LCD_WriteData(bColor);
                }
                // ����һλ
                tempByte >>= 1;
            }
        }
    }
}

// 3.2 ��ʾ�ַ���
void LCD_WriteAsciiString(uint16_t x, uint16_t y, uint16_t height, uint8_t *str, uint16_t fColor, uint16_t bColor)
{
    // ����һ��������ָ����ǰ�������ַ�
    uint8_t i = 0;

    // ����\0��־�ж��ַ����Ƿ����
    while (str[i] != '\0')
    {
        // �ж��Ƿ�����\n��Ҫ���У����û��������ֱ������x��������ʾ
        if (str[i] != '\n')
        {
            // �����ж�һ���Ƿ񵽴ﵱǰ�е�ĩβ�����Ҫ�����߽���Զ�����
            if (x + height / 2 > LCD_W)
            {
                // ����
                x = 0;
                y += height;
            }

            LCD_WriteAsciiChar(x, y, height, str[i], fColor, bColor);
            x += height / 2;
        }
        else
        {
            // ����
            x = 0;
            y += height;
        }
        i++;
    }
}

// 3.3 ��ʾһ�������ַ�
void LCD_WriteChineseChar(uint16_t x, uint16_t y, uint16_t height, uint8_t index, uint16_t fColor, uint16_t bColor)
{
    // ������ʾ����
    LCD_SetArea(x, y, height, height);

    // ����ָ��
    LCD_WriteCmd(0x2C);

    // ��������
    // ����ÿһ�У�ÿһ�У�˫��ѭ������Ҫ�����height������ 32
    for (uint8_t i = 0; i < 128; i++)
    {
        // ���������С�����ֿ���ѡ��ǰ�ж�Ӧ�ĵ�i���ֽڣ�����ǵ�i�еĵ���
        uint8_t tempByte = chinese[index][i];

        //  ������ǰ�ֽ��е�ÿһ�У�ÿ�����ص� - �ֽ��е�ÿһλ��
        for (uint8_t j = 0; j < 8; j++)
        {
            // ÿ��ֻȡ���λ
            if (tempByte & 0x01)
            {
                // �����1����ʾ������ɫ
                LCD_WriteData(fColor);
            }
            else
            {
                // �����0����ʾ������ɫ
                LCD_WriteData(bColor);
            }
            // ����һλ
            tempByte >>= 1;
        }
    }
}

// 3.4 ��ʾͼƬ
void LCD_DisplayAtguiguLogo(uint16_t x, uint16_t y)
{
    // ������ʾ����
    LCD_SetArea(x, y, 227, 68);

    // ����ָ��
    LCD_WriteCmd(0x2C);

    uint16_t len = sizeof(gImage_logo);

    // ÿ��ȡ�����ֽڣ�ƴ�ӳ�һ�����ص��RGB����
    for (uint16_t i = 0; i < len; i += 2)
    {
        // 16λ��ʾһ�����ص㣬��λ��ǰ����λ�ں�
        uint16_t p = gImage_logo[i] + (gImage_logo[i + 1] << 8);
        LCD_WriteData(p);
    }
}

// 3.5 ����һ���㣬�������Ͻ���ʼ������꣬�Լ�����Ŀ���
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t w, uint16_t color)
{
    // 1. ��������
    LCD_SetArea(x, y, w, w);

    // 2. ��������
    LCD_WriteCmd(0x2C);

    // 3. ���������������ص�Ϳ�ϸ�������ɫ
    for (uint16_t i = 0; i < w * w; i++)
    {
        LCD_WriteData(color);
    }
}

// 3.6 ����һ���ߣ����������յ������
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t w, uint16_t color)
{
    // ����ֱ�߷����е�k��b
    // y = kx + b, k = (y1-y2)/(x1-x2), b = y1 - k * x1

    // �ȿ���x1 == x2 �������һ������
    if (x1 == x2)
    {
        for (uint16_t y = y1; y <= y2; y++)
        {
            LCD_DrawPoint(x1, y, w, color);
        }
        return;
    }

    // �ȼ���k �� b
    double k = 1.0 * (y1 - y2) / (x1 - x2);
    double b = y1 - k * x1;

    // ����ֱ�߷��̣����λ��㣨Ĭ��Ҫ��x1 <= x2��
    for (uint16_t x = x1; x <= x2; x++)
    {
        uint16_t y = (uint16_t)(k * x + b);
        LCD_DrawPoint(x, y, w, color);
    }
}

// 3.7 ����һ��������
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t w, uint16_t color)
{
    LCD_DrawLine(x1, y1, x2, y1, w, color);
    LCD_DrawLine(x2, y1, x2, y2, w, color);
    LCD_DrawLine(x1, y1, x1, y2, w, color);
    LCD_DrawLine(x1, y2, x2, y2, w, color);
}

// 3.8 ��Բ������Բ�������Լ��뾶
void LCD_DrawCircle(uint16_t xCenter, uint16_t yCenter, uint16_t r, uint16_t w, uint16_t color)
{
    // ���ռ����귽�̣�����ÿһ����
    // x = x0 + rcos��
    // y = y0 + rsin��
    for (uint16_t theta = 0; theta < 360; theta++)
    {
        uint16_t x = xCenter + r * cos(3.14 * theta / 180);
        uint16_t y = yCenter + r * sin(3.14 * theta / 180);

        LCD_DrawPoint(x, y, w, color);
    }
}

// ��Բ�Ż�ʵ�֣�ͬʱ����4�����޵ĵ�
void LCD_DrawCircle_Pro(uint16_t xCenter, uint16_t yCenter, uint16_t r, uint16_t w, uint16_t color)
{
    // ���ռ����귽�̣�����ÿһ����
    // x = x0 + rcos��
    // y = y0 + rsin��
    for (uint16_t theta = 0; theta <= 90; theta++)
    {
        uint16_t delta_x = r * cos(3.14 * theta / 180);
        uint16_t delta_y = r * sin(3.14 * theta / 180);

        // ��һ����
        uint16_t x = xCenter + delta_x;
        uint16_t y = yCenter + delta_y;

        LCD_DrawPoint(x, y, w, color);

        // �ڶ�����
        x = xCenter - delta_x;
        y = yCenter + delta_y;

        LCD_DrawPoint(x, y, w, color);

        // ��������
        x = xCenter - delta_x;
        y = yCenter - delta_y;

        LCD_DrawPoint(x, y, w, color);

        // ��������
        x = xCenter + delta_x;
        y = yCenter - delta_y;

        LCD_DrawPoint(x, y, w, color);
    }
}

// 3.9 ��ʵ��Բ
void LCD_DrawFilledCircle(uint16_t xCenter, uint16_t yCenter, uint16_t r, uint16_t w, uint16_t bColor, uint16_t fColor)
{
    // ��rȡ��ͬ��ֵ�����λ�����Բ
    for (uint16_t i = 0; i <= r; i++)
    {
        for (uint16_t theta = 0; theta < 360; theta++)
        {
            uint16_t x = xCenter + i * cos(3.14 * theta / 180);
            uint16_t y = yCenter + i * sin(3.14 * theta / 180);

            if (i == r)
            {
                LCD_DrawPoint(x, y, w, fColor);
            }
            else
            {
                LCD_DrawPoint(x, y, w, bColor);
            }
        }
    }
}

// ʵ��Բ�Ż�
void LCD_DrawFilledCircle_Pro(uint16_t xCenter, uint16_t yCenter, uint16_t r, uint16_t w, uint16_t bColor, uint16_t fColor)
{
    // �����ĸ������ҵ�4���㣬ֱ�ӻ���������
        for (uint16_t theta = 0; theta <= 90; theta++)
    {
        uint16_t delta_x = r * cos(3.14 * theta / 180);
        uint16_t delta_y = r * sin(3.14 * theta / 180);

        // ��һ����
        uint16_t x1 = xCenter + delta_x;
        uint16_t y1 = yCenter + delta_y;

        LCD_DrawPoint(x1, y1, w, fColor);

        // �ڶ�����
        uint16_t x2 = xCenter - delta_x;
        uint16_t y2 = yCenter + delta_y;

        LCD_DrawPoint(x2, y2, w, fColor);

        // ������������һ��ֱ��
        LCD_DrawLine(x2 + w, y2, x1 - w, y1, w, bColor);

        // ��������
        x2 = xCenter - delta_x;
        y2 = yCenter - delta_y;

        LCD_DrawPoint(x2, y2, w, fColor);

        // ��������
        x1 = xCenter + delta_x;
        y1 = yCenter - delta_y;

        LCD_DrawPoint(x1, y1, w, fColor);

        // ������������һ��ֱ��
        LCD_DrawLine(x2 + w, y2, x1 - w, y1, w, bColor);
    }
}
